Physical memory access reservation for safe memory API#824
Conversation
420bea6 to
d0c665c
Compare
8b9b1f7 to
3a833f2
Compare
41e36c2 to
a6c1102
Compare
2473ace to
27bb1dd
Compare
24fcce1 to
3dc8650
Compare
24e1d87 to
9b0f0f0
Compare
6dbe423 to
f6d2dc0
Compare
|
ℹ️ Note: This semver check was run against the 🤖 SemverChecks 🤖 Click for details |
|
@CvvT I think we should take a look at this PR as well. Thanks! |
wdcui
left a comment
There was a problem hiding this comment.
I left some comments below. I'm confident about my review because this PR has a lot of subtlties, so I didn't approve it and asked Weiteng to take a look at it as well.
| exec_ranges: Option<&[Range<PhysAddr>]>, | ||
| ) -> Result<*mut u8, MapToError<Size4KiB>> { | ||
| self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct) | ||
| self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct, true) |
There was a problem hiding this comment.
Why does this function need rollback but map_phys_frame_range doesn't
There was a problem hiding this comment.
All these rollback stuffs are some kinds of patching. It doesn't try to modify existing logic as much as possible. Technically, most of these mapping failures are critical bugs and rollbacks are just best-effort mitigation.
There was a problem hiding this comment.
Seems that it is better not to deal with rollback in this PR.
| /// We might need to emulate these functions' behaviors using virtual addresses for development or | ||
| /// testing, or use a kernel module to provide this functionality (if needed). | ||
| impl<const ALIGN: usize> VmapManager<ALIGN> for LinuxUserland {} | ||
| unsafe impl<const ALIGN: usize> VmapManager<ALIGN> for LinuxUserland { |
There was a problem hiding this comment.
This trait has some safety requirements which cannot be easily enforced by Rust code.
| /// requested physical pages in order, that the returned [`Self::MapInfo`] owns the mapping and any | ||
| /// access reservation needed for the mapping lifetime, and that [`Self::vunmap`] does not release | ||
| /// that reservation unless the mapping has been invalidated or safely retained in the returned | ||
| /// [`Self::MapInfo`]. Implementors must also ensure [`Self::validate_unowned`] rejects physical |
There was a problem hiding this comment.
Nit: the last sentence needs some fix?
| PhysFrame::<Size4KiB>::containing_address(frame.start_address()), | ||
| )); | ||
| } | ||
| if rollback_on_error { |
There was a problem hiding this comment.
For the branch on line 583, there is no rollback?
There was a problem hiding this comment.
At this point (line 583), everything is pretty blur because something unexpected exists in the page table (a critical bug). We can still rollback some partial mappings, though. Let me do this.
| #[error("Page-table frame allocation failed (out of memory)")] | ||
| FrameAllocationFailed, | ||
| #[error("Physical address range starting at {0:#x} is already locked")] | ||
| PhysicalAddressRangeLocked(usize), |
There was a problem hiding this comment.
This error is not properly converted in litebox_common_optee/src/lib.rs:2289?
There was a problem hiding this comment.
EBusy might be better for this error.
| let mut inner = PHYS_RANGE_RESERVATIONS.lock(); | ||
| for range in &self.ranges { | ||
| if let Some(index) = inner.entries.iter().position(|entry| entry == range) { | ||
| inner.entries.swap_remove(index); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Related to my early comment: the leak of PhysPageMapInfo is to prevent calling this Drop. Should we make it explicit, e.g., PhyMutPtr requires implementing remove_range? Then we don't need to leak memory on the failure path.
There was a problem hiding this comment.
It does. PhysPtr's unmap (drop) calls page table's unmap eventually. This leak is mostly about page-table-level unmap failure, and we cannot avoid memory leak at this point.
| // SAFETY: The platform is expected to handle unmapping safely. Drop cannot | ||
| // report errors, so a failed unmap leaves map_info restored in the owner and | ||
| // is only reported by debug assertion. | ||
| let result = unsafe { self.owner.unmap() }; |
There was a problem hiding this comment.
MappedGuard's Drop calls PhyMutPtr's unmap, and when the PhyMutPtr drops, it also calls unmap?
There was a problem hiding this comment.
yes. PhysPtr's unmap -> Vmap's vunmap -> page table's unmap.
This PR adds support for physical memory access reservation, which is the last piece to make the VTL0/normal-world physical memory access API "safe". Now, our API is safe in the DMA/shared-memory sense:
External agents (VTL0, hypervisor, peripherals, ...) can still access those physical addresses but this is out of LiteBox/Rust's control. We do have the
protectmethod to prevent VTL0's access to them if needed.